package com.knight.spring.framework.beans.factory.support;

import com.knight.spring.framework.annotation.KnightController;
import com.knight.spring.framework.annotation.KnightService;
import com.knight.spring.framework.beans.config.KnightBeanDefinition;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class KnightBeanDefinitionReader {

    private String[] configurationList;

    //固定配置文件中的key，相对于xml的规范
    private final String SCAN_PACKAGE = "scanPackage";
    List<String> registryBeanClass = new ArrayList<>();

    private Properties config = new Properties();

    public KnightBeanDefinitionReader(String[] configurationList) {
        //通过URL定位找到其所对应的文件，然后转换为文件流
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(configurationList[0].replace("classpath" +
                ":",""));
        try {
            config.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        doScan(config.getProperty(SCAN_PACKAGE));

    }

    private void doScan(String scanPackage) {
        //将.替换成/
        URL url = this.getClass().getClassLoader().getResource(scanPackage.replaceAll("\\.","/"));
        File classPath = new File(url.getFile());
        for (File file : classPath.listFiles()) {
            if(file.isDirectory()){
                doScan(scanPackage+"."+file.getName());
            }else{
                if(!file.getName().endsWith(".class")){
                    continue;
                }
                //拼接成com.knight.Test
                String className = scanPackage+"."+file.getName().replace(".class","");
                registryBeanClass.add(className);
            }
        }

    }

    public List<KnightBeanDefinition> loadBeanDefinitions() {
        List<KnightBeanDefinition> beanDefinitions = new ArrayList<>();
        for (String beanClassName : registryBeanClass) {
            try {
                Class<?> beanClass = Class.forName(beanClassName);
                //如果是接口不能实例化
                if (beanClass.isInterface()) {
                    continue;
                }
                if (!(beanClass.isAnnotationPresent(KnightController.class) || beanClass.isAnnotationPresent(KnightService.class))) {
                    continue;
                }
                String beanName = null;
                if (beanClass.getAnnotation(KnightService.class)!=null) {
                    beanName = beanClass.getAnnotation(KnightService.class).value();
                }else if(beanClass.getAnnotation(KnightController.class)!=null){
                    beanName = beanClass.getAnnotation(KnightController.class).value();
                }else{
                    Class<?> [] interfaces = beanClass.getInterfaces();
                    for (Class<?> i : interfaces) {
                        beanDefinitions.add(doCreateBeanDefinition(toLowerFirstCase(i.getName()),
                                beanClass.getName(),beanName));
                    }
                }
                beanDefinitions.add(doCreateBeanDefinition(toLowerFirstCase(beanClass.getSimpleName()),
                        beanClass.getName(),beanName));


            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return beanDefinitions;
    }

    private KnightBeanDefinition doCreateBeanDefinition(String factoryBeanName, String beanClassName,String beanName) {
        KnightBeanDefinition knightBeanDefinition = new KnightBeanDefinition();
        knightBeanDefinition.setBeanClassName(beanClassName);
        knightBeanDefinition.setFactoryBeanName(factoryBeanName);
        knightBeanDefinition.setBeanName(beanName);
        return knightBeanDefinition;
    }

    /**
     *     如果类名本身是小写字母，确实会出问题
     *     但是我要说明的是：这个方法是我自己用，private的
     *     //传值也是自己传，类也都遵循了驼峰命名法
     *     //默认传入的值，存在首字母小写的情况，也不可能出现非字母的情况
     *      *
     *     //为了简化程序逻辑，就不做其他判断了，大家了解就OK
     * @param simpleName
     * @return
     */
    private String toLowerFirstCase(String simpleName) {
        char[] chars = simpleName.toCharArray();
        chars[0]+=32;
        return String.valueOf(chars);
    }

    public Properties getConfig() {
        return config;
    }
}
